package com.weareint.common.utils;

import com.alibaba.fastjson.JSONObject;
import com.weareint.common.vo.Result;
import org.apache.commons.codec.digest.DigestUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/** 校验码 */
public abstract class CheckSumUtil {

    private static final String RANDOM_SEED =
            "5c70b2734f6767ffeb5c7a83e1b30e89541247e0aacee8ea840b940c15b39276";

    /**
     * @param result result vm
     * @return checksum
     */
    public static String checksum(Result result) {
        String content =
                result.getMsg() + result.getCode() + JSONObject.toJSONString(result.getData());
        return internalChecksum(content);
    }

    /**
     *
     *
     * <pre>
     *     1. 对字符串content的长度求因数，并从小到大排序，得数组 idxes
     *     2. 提取出字符串content中的所有字母数据下划线[a-zA-Z_0-9]，是字符串buffer
     *     3. 把buffer转为字符数组，再从小到大排序，再转为字符串得 sorted
     *     4. 以idxes数组元素值为下标，获取sorted对应位置的字符。
     *     5. 如果idxes数组元素值大于sorted长度，那么idxeds[i] % sorted.length()
     *     6. 最后对sorted中取出的子字符做md5
     * </pre>
     *
     * @param content content
     * @return md5
     */
    private static String internalChecksum(String content) {
        // 取出字符串长的所有因数
        int[] idxes = indexes(content.length());
        StringBuilder buffer = new StringBuilder();
        // 取出 [a-zA-Z_0-9]
        //noinspection AlibabaAvoidPatternCompileInMethod
        Matcher matcher = Pattern.compile("(\\w+)").matcher(content);
        while (matcher.find()) {
            buffer.append(matcher.group());
        }
        char[] chars = buffer.toString().toCharArray();
        Arrays.sort(chars);
        String sorted = new String(chars);

        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < idxes.length; i++) {
            // 当超过sorted长度时，对sorted.length 做模运算。
            int idx = idxes[i] >= sorted.length() ? idxes[i] % sorted.length() : idxes[i];
            builder.append(sorted.charAt(idx));
        }
        return DigestUtils.md5Hex(builder.toString() + RANDOM_SEED);
    }

    /**
     * <pre>
     *      长度因数，从小到大排序
     * </pre>
     * @param n len
     * @return int[]
     */
    private static int[] indexes(int n) {
        List<Integer> list = new ArrayList<>();
        for (int i = 1; i <= Math.sqrt(n); i++) {
            if (n % i == 0) {
                list.add(i);
                if (n != i * i) {
                    list.add(n / i);
                }
            }
        }
        int[] array = list.stream().mapToInt(value -> value).toArray();
        Arrays.sort(array);
        return array;
    }
}
